#include <51func.h>
typedef struct connInfo_s {
    int fd;
    int isValid; // 0 未使用or已经关闭 1 正在使用的
    time_t lastActive;
} connInfo_t;
int main(int argc, char *argv[])
{
    // ./1_azhen 192.168.118.128 1234
    ARGS_CHECK(argc,3);
    // socket
    int sockfd = socket(AF_INET,SOCK_STREAM,0);
    struct sockaddr_in serverAddr;
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = htons(atoi(argv[2]));
    serverAddr.sin_addr.s_addr = inet_addr(argv[1]);
    // setsockopt
    int arg = 1; // REUSEADDR的参数值为真
    int ret = setsockopt(sockfd,SOL_SOCKET,
                         SO_REUSEADDR,&arg,sizeof(arg));
    ERROR_CHECK(ret,-1,"setsockopt");
    // bind
    ret = bind(sockfd,(struct sockaddr *)&serverAddr,sizeof(serverAddr));
    ERROR_CHECK(ret,-1,"bind");
    // listen
    listen(sockfd,10);
    // accept
    struct sockaddr_in clientAddr;
    socklen_t clientAddrLength = sizeof(clientAddr); //必须赋初值
    
    connInfo_t connInfo[1024];//存储所有客户端连接的信息
    for(int i = 0; i < 1024; ++i){
        connInfo[i].isValid = 0;
    }
    int curidx = 0; //下一个要放入的netfd的下标
    
    char buf[4096];
    fd_set monitorset;
    fd_set readyset;
    FD_ZERO(&monitorset);
    FD_SET(sockfd,&monitorset);
    while(1){
        memcpy(&readyset,&monitorset,sizeof(fd_set));
        struct timeval timeout;
        timeout.tv_sec = 1;
        timeout.tv_usec = 0;
        select(1024,&readyset,NULL,NULL,&timeout);
        time_t curtime = time(NULL);
        printf("curtime = %s\n", ctime(&curtime));
        if(FD_ISSET(sockfd,&readyset)){
            int netfd  = accept(sockfd,(struct sockaddr *)&clientAddr,&clientAddrLength);
            printf("client ip = %s, port = %d\n",
                           inet_ntoa(clientAddr.sin_addr),ntohs(clientAddr.sin_port));
            connInfo[curidx].fd = netfd;
            connInfo[curidx].isValid = 1;
            connInfo[curidx].lastActive = time(NULL);
            FD_SET(netfd,&monitorset);
            ++curidx;
        }
        for(int i = 0; i < curidx; ++i){//遍历所有的netfd
            if(connInfo[i].isValid == 1 && FD_ISSET(connInfo[i].fd,&readyset)){//某个netfd就绪
                bzero(buf,sizeof(buf));
                ssize_t sret = recv(connInfo[i].fd,buf,sizeof(buf),0);//读取出来
                if(sret == 0){ // netfd 断开
                    FD_CLR(connInfo[i].fd,&monitorset);
                    close(connInfo[i].fd);
                    connInfo[i].isValid = 0;
                    continue;
                }
                for(int j = 0; j < curidx; ++j){
                    if(j == i || connInfo[j].isValid == 0){
                        continue;
                    }
                    //转发给了除了自己以及已经断开的所有netfd
                    send(connInfo[j].fd,buf,strlen(buf),0);
                }
                connInfo[i].lastActive = time(NULL);
            }
        }
        // 踢人
        for(int i = 0; i < curidx; ++i){
            if(connInfo[i].isValid == 0){
                continue;
            }
            if(curtime - connInfo[i].lastActive > 10){
                FD_CLR(connInfo[i].fd,&monitorset);
                close(connInfo[i].fd);
                connInfo[i].isValid = 0;
            } 
        }
    }
    return 0;
}

